﻿using System;
using System.Collections.Generic;

namespace Activity.II
{
	/// <summary>
	/// Базовый класс компьютера для хостинга игрового сервера.
	/// </summary>
	public abstract class Computer
	{
		protected static Random random = new Random();

		/// <summary>
		/// Создать новый экземпляр сервера.
		/// </summary>
		/// <param name="name">Название сервера.</param>
		protected Computer (string name)
		{
			Name = name;
		}

		/// <summary>
		/// Список возможных ошибок при хостинге сервера.
		/// </summary>
		protected readonly List<int> errors = new List<int>();

		/// <summary>
		/// Название сервера.
		/// </summary>
		public string Name { get; private set; }

		/// <summary>
		/// Описание сервера.
		/// </summary>
		public string Description { get; set; }

		/// <summary>
		/// Список активных игроков на сервере.
		/// </summary>
		public List<string> Players { get; protected set; }

		/// <summary>
		/// История операций и ошибок сервера.
		/// </summary>
		public string History { get; private set; }

		/// <summary>
		/// Подключить игрока к серверу.
		/// </summary>
		/// <param name="playerName">Имя игрока.</param>
		/// <returns>Истина при успешном подключении, в противном случае ложь.</returns>
		public abstract bool Connect (string playerName);

		/// <summary>
		/// Отключить игрока от сервера.
		/// </summary>
		/// <param name="playerName">Имя игрока.</param>
		public void Disconnect (string playerName)
		{
			if (!Players.Remove(playerName))
				Log(string.Format("Игрок с именем {0} не найден!", playerName));
			else
				Log(string.Format("Игрок {0} покинул игру!", playerName));
		}

		/// <summary>
		/// Нормализованная загрузка сервер (от 0 до 1);
		/// </summary>
		public float GetLoad ()
		{
			return (float)Players.Count / Players.Capacity;
		}

		/// <summary>
		/// Отправить сообщение в историю сервера.
		/// </summary>
		/// <param name="message">Текст сообщения.</param>
		public void Log (string message)
		{
			History = string.Format("[{0}]: {1}\r\n", DateTime.Now.ToString("hh:mm:ss"), message) + History;
		}

		/// <summary>
		/// Создать случайную ошибку.
		/// </summary>
		/// <returns>Возвращает сообщение с пояснением об ошибке.</returns>
		protected string CreateError ()
		{
			// Генерируем случайный индекс ошибки
			var index = random.Next(-1, errors.Count);

			// Оставляем возможность для генерации не известной ошибки
			if (index < 0)
			{
				index = random.Next(1000, 2000);
				return GetError(index);
			}

			// Получаем расшифровку ошибки
			return GetError(errors[index]);
		}

		/// <summary>
		/// Расшифровать код ошибки.
		/// </summary>
		/// <param name="error">Код ошибки.</param>
		/// <returns>Возвращает текст поясняющий причину ошибки.</returns>
		public static string GetError (int error)
		{
			var prefix = "Ошибка сервера #" + error + ": ";
			switch (error)
			{
				case (int)Error.BadRequest:
					return prefix + "Неверный запрос!";

				case (int)Error.NotFound:
					return prefix + "Сервер не найден!";

				case (int)Error.RequestTimeout:
					return prefix + "Истекло время ожидания подключения!";

				case (int)Error.TooManyRequests:
					return prefix + "Слишком много запросов, попробуйте позже!";

				case (int)Error.InternalServerError:
					return prefix + "Внутренняя ошибка сервера!";

				case (int)Error.ServiceUnavailable:
					return prefix + "Сервер не доступен!";

				case (int)Error.GatewayTimeout:
					return prefix + "Шлюз не отвечает!";

				case (int)Error.BandwidthLimitExceeded:
					return prefix + "Исчерпана пропускная ширина канала!";

				default:
					return string.Format("Ошибка: не известная ошибка сервера #{0}!", error);
			}
		}

		/// <summary>
		/// Перечисление известных ошибок сервера.
		/// </summary>
		public enum Error
		{
			BadRequest = 400,
			NotFound = 404,
			RequestTimeout = 408,
			TooManyRequests = 429,
			InternalServerError = 500,
			ServiceUnavailable = 503,
			GatewayTimeout = 504,
			BandwidthLimitExceeded = 509,
		}
	}
}
